package com.pro01.apirednote.service.serviceImpl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.pro01.apirednote.pojo.Content;
import com.pro01.apirednote.pojo.PageResult;
import com.pro01.apirednote.pojo.Result;
import com.pro01.apirednote.service.CacheService;
import com.pro01.apirednote.service.ChineseVectorService;
import com.pro01.apirednote.service.ElasticsearchService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.entity.ContentType;
import org.apache.http.nio.entity.NStringEntity;
import org.apache.http.util.EntityUtils;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.ResponseException;
import org.elasticsearch.client.RestClient;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class ElasticsearchServiceImpl implements ElasticsearchService {

    private final RestClient restClient;
    private final ObjectMapper objectMapper;
    private final ChineseVectorService chineseVectorService;
    private final CacheService cacheService;
    private static final String CONTENT_INDEX = "contents";
    private boolean elasticsearchAvailable = true;
    // 搜索结果缓存时间（秒）
    private static final long SEARCH_CACHE_EXPIRY = 300; // 5分钟

    @Override
    public void createContentIndex() {
        if (!elasticsearchAvailable) {
            log.warn("Elasticsearch不可用，跳过创建索引");
            return;
        }

        try {
            // 检查索引是否存在
            boolean exists = indexExists(CONTENT_INDEX);

            if (!exists) {
                // 创建索引，添加向量字段支持
                String mappingJson = "{\n" +
                        "  \"settings\": {\n" +
                        "    \"number_of_shards\": 1,\n" +
                        "    \"number_of_replicas\": 0\n" +
                        "  },\n" +
                        "  \"mappings\": {\n" +
                        "    \"properties\": {\n" +
                        "      \"id\": { \"type\": \"long\" },\n" +
                        "      \"userId\": { \"type\": \"long\" },\n" +
                        "      \"title\": { \n" +
                        "        \"type\": \"text\",\n" +
                        "        \"analyzer\": \"ik_max_word\",\n" +
                        "        \"search_analyzer\": \"ik_smart\",\n" +
                        "        \"fields\": {\n" +
                        "          \"keyword\": { \n" +
                        "            \"type\": \"keyword\",\n" +
                        "            \"ignore_above\": 256\n" +
                        "          }\n" +
                        "        }\n" +
                        "      },\n" +
                        "      \"type\": { \"type\": \"keyword\" },\n" +
                        "      \"description\": { \n" +
                        "        \"type\": \"text\",\n" +
                        "        \"analyzer\": \"ik_max_word\",\n" +
                        "        \"search_analyzer\": \"ik_smart\",\n" +
                        "        \"fields\": {\n" +
                        "          \"keyword\": { \n" +
                        "            \"type\": \"keyword\",\n" +
                        "            \"ignore_above\": 256\n" +
                        "          }\n" +
                        "        }\n" +
                        "      },\n" +
                        "      \"searchText\": { \n" +
                        "        \"type\": \"text\",\n" +
                        "        \"analyzer\": \"ik_max_word\",\n" +
                        "        \"search_analyzer\": \"ik_smart\"\n" +
                        "      },\n" +
                        "      \"content_vector\": { \n" +
                        "        \"type\": \"dense_vector\",\n" +
                        "        \"dims\": 300,\n" +
                        "        \"index\": true,\n" +
                        "        \"similarity\": \"cosine\"\n" +
                        "      },\n" +
                        "      \"likeCount\": { \"type\": \"integer\" },\n" +
                        "      \"commentCount\": { \"type\": \"integer\" },\n" +
                        "      \"viewCount\": { \"type\": \"integer\" },\n" +
                        "      \"isDeleted\": { \"type\": \"boolean\" },\n" +
                        "      \"createdAt\": { \"type\": \"date\" },\n" +
                        "      \"updatedAt\": { \"type\": \"date\" }\n" +
                        "    }\n" +
                        "  }\n" +
                        "}";

                Request request = new Request("PUT", "/" + CONTENT_INDEX);
                request.setEntity(new NStringEntity(mappingJson, ContentType.APPLICATION_JSON));
                Response response = restClient.performRequest(request);
                
                int statusCode = response.getStatusLine().getStatusCode();
                log.info("创建索引结果: {}", statusCode);
            }
        } catch (IOException e) {
            handleElasticsearchException("创建索引失败", e);
        }
    }

    private boolean indexExists(String indexName) throws IOException {
        try {
            Request request = new Request("HEAD", "/" + indexName);
            Response response = restClient.performRequest(request);
            return response.getStatusLine().getStatusCode() == 200;
        } catch (ResponseException e) {
            if (e.getResponse().getStatusLine().getStatusCode() == 404) {
                return false;
            }
            throw e;
        } catch (IOException e) {
            handleElasticsearchException("检查索引是否存在失败", e);
            return false;
        }
    }

    @Override
    public void indexContent(Content content) {
        if (!elasticsearchAvailable) {
            log.warn("Elasticsearch不可用，跳过索引内容");
            return;
        }

        if (content == null || content.getId() == null) {
            log.error("无法索引内容：内容对象或ID为空");
            return;
        }

        log.info("开始索引内容到ES，ID: {}, 标题: {}", content.getId(), content.getTitle());
        try {
            // 设置搜索文本
            String searchText = content.getSearchText();
            log.debug("内容ID: {} 的搜索文本: {}", content.getId(), searchText);
            
            // 为内容生成向量
            Map<String, Object> contentMap = objectMapper.convertValue(content, Map.class);
            
            // 添加搜索文本字段
            contentMap.put("searchText", searchText);
            
            // 如果向量服务可用，则生成向量
            if (chineseVectorService.isModelLoaded()) {
                String textForVector = content.getTitle() + " " + content.getDescription();
                log.debug("为内容ID: {}生成向量，文本长度: {}", content.getId(), textForVector.length());
                double[] vector = chineseVectorService.textToVector(textForVector);
                contentMap.put("content_vector", vector);
                log.debug("成功为内容ID: {}生成向量", content.getId());
            } else {
                log.warn("词向量模型未加载，内容ID: {}将不包含向量信息", content.getId());
            }
            
            String contentJson = objectMapper.writeValueAsString(contentMap);
            Request request = new Request("PUT", "/" + CONTENT_INDEX + "/_doc/" + content.getId());
            request.setEntity(new NStringEntity(contentJson, ContentType.APPLICATION_JSON));
            
            log.debug("发送索引请求到ES，内容ID: {}", content.getId());
            Response response = restClient.performRequest(request);
            int statusCode = response.getStatusLine().getStatusCode();
            
            if (statusCode >= 200 && statusCode < 300) {
                log.info("内容索引成功，ID: {}, 状态码: {}", content.getId(), statusCode);
                
                // 添加刷新索引的操作，确保新内容立即可搜索
                refreshIndex("添加", content.getId());
            } else {
                log.warn("内容索引返回非成功状态码，ID: {}, 状态码: {}", content.getId(), statusCode);
            }
        } catch (IOException e) {
            log.error("索引内容失败，ID: {}, 错误: {}", content.getId(), e.getMessage(), e);
            handleElasticsearchException("索引内容失败", e);
        } catch (Exception e) {
            log.error("索引内容时发生未预期的错误，ID: {}, 错误: {}", content.getId(), e.getMessage(), e);
        }
    }

    @Override
    public void updateIndexedContent(Content content) {
        if (!elasticsearchAvailable) {
            log.warn("Elasticsearch不可用，跳过更新索引内容");
            return;
        }

        try {
            // 为内容生成向量
            Map<String, Object> contentMap = objectMapper.convertValue(content, Map.class);
            
            // 如果向量服务可用，则生成向量
            if (chineseVectorService.isModelLoaded()) {
                String textForVector = content.getTitle() + " " + content.getDescription();
                double[] vector = chineseVectorService.textToVector(textForVector);
                contentMap.put("content_vector", vector);
            }
            
            String contentJson = objectMapper.writeValueAsString(contentMap);
            Request request = new Request("PUT", "/" + CONTENT_INDEX + "/_doc/" + content.getId());
            request.setEntity(new NStringEntity(contentJson, ContentType.APPLICATION_JSON));
            Response response = restClient.performRequest(request);
            int statusCode = response.getStatusLine().getStatusCode();
            
            if (statusCode >= 200 && statusCode < 300) {
                log.info("更新索引内容成功，ID: {}, 状态码: {}", content.getId(), statusCode);
                
                // 刷新索引，确保更新立即可见
                refreshIndex("更新", content.getId());
            } else {
                log.warn("更新索引内容返回非成功状态码，ID: {}, 状态码: {}", content.getId(), statusCode);
            }
        } catch (IOException e) {
            handleElasticsearchException("更新索引内容失败", e);
        }
    }

    @Override
    public void deleteIndexedContent(Long contentId) {
        if (!elasticsearchAvailable) {
            log.warn("Elasticsearch不可用，跳过删除索引内容");
            return;
        }

        try {
            Request request = new Request("DELETE", "/" + CONTENT_INDEX + "/_doc/" + contentId);
            Response response = restClient.performRequest(request);
            int statusCode = response.getStatusLine().getStatusCode();
            
            if (statusCode >= 200 && statusCode < 300) {
                log.info("删除索引内容成功，ID: {}, 状态码: {}", contentId, statusCode);
                
                // 刷新索引，确保删除立即生效
                refreshIndex("删除", contentId);
            } else {
                log.warn("删除索引内容返回非成功状态码，ID: {}, 状态码: {}", contentId, statusCode);
            }
        } catch (IOException e) {
            handleElasticsearchException("删除索引内容失败", e);
        }
    }

    @Override
    public Result<PageResult<Content>> searchContent(String keyword, int pageNum, int pageSize) {
        if (!elasticsearchAvailable) {
            log.warn("Elasticsearch不可用，使用数据库搜索");
            // 返回空结果，前端可以降级到使用数据库搜索
            return Result.error("Elasticsearch服务不可用，请使用普通搜索");
        }

        try {
            // 尝试从缓存中获取搜索结果
            String cacheKey = cacheService.generateSearchKey("es", keyword, pageNum, pageSize);
            PageResult<Content> cachedResult = cacheService.getCachedSearchResult(cacheKey);
            
            if (cachedResult != null) {
                log.info("使用缓存的搜索结果: {}", cacheKey);
                return Result.success(cachedResult);
            }
            
            log.info("缓存未命中，执行Elasticsearch搜索: {}", cacheKey);
            
            // 计算起始位置
            int from = (pageNum - 1) * pageSize;
            
            // 构建查询 - 使用更灵活的匹配策略和精确的术语查询
            String queryJson = "{\n" +
                    "  \"from\": " + from + ",\n" +
                    "  \"size\": " + pageSize + ",\n" +
                    "  \"query\": {\n" +
                    "    \"bool\": {\n" +
                    "      \"should\": [\n" +
                    "        { \"match\": { \"title\": \"" + keyword + "\" } },\n" +
                    "        { \"match\": { \"description\": \"" + keyword + "\" } },\n" +
                    "        { \"match\": { \"searchText\": \"" + keyword + "\" } },\n" +
                    "        { \"match_phrase\": { \"title\": \"" + keyword + "\" } },\n" +
                    "        { \"match_phrase\": { \"description\": \"" + keyword + "\" } },\n" +
                    "        { \"match_phrase\": { \"searchText\": \"" + keyword + "\" } },\n" +
                    "        { \"wildcard\": { \"title\": \"*" + keyword + "*\" } },\n" +
                    "        { \"wildcard\": { \"description\": \"*" + keyword + "*\" } },\n" +
                    "        { \"term\": { \"title.keyword\": \"" + keyword + "\" } },\n" +
                    "        { \"multi_match\": { \"query\": \"" + keyword + "\", \"fields\": [\"title\", \"description\", \"searchText\"], \"type\": \"best_fields\", \"fuzziness\": \"AUTO\" } }\n" +
                    "      ],\n" +
                    "      \"minimum_should_match\": 1,\n" +
                    "      \"filter\": [\n" +
                    "        { \"term\": { \"isDeleted\": false } }\n" +
                    "      ]\n" +
                    "    }\n" +
                    "  },\n" +
                    "  \"sort\": [\n" +
                    "    { \"_score\": { \"order\": \"desc\" } },\n" +
                    "    { \"createdAt\": { \"order\": \"desc\" } }\n" +
                    "  ],\n" +
                    "  \"highlight\": {\n" +
                    "    \"fields\": {\n" +
                    "      \"title\": {},\n" +
                    "      \"description\": {}\n" +
                    "    }\n" +
                    "  }\n" +
                    "}";
            
            log.debug("执行ES搜索查询: {}", queryJson);
            
            // 执行搜索
            Request request = new Request("POST", "/" + CONTENT_INDEX + "/_search");
            request.setEntity(new NStringEntity(queryJson, ContentType.APPLICATION_JSON));
            Response response = restClient.performRequest(request);
            
            // 解析结果
            String responseBody = EntityUtils.toString(response.getEntity());
            log.debug("ES搜索响应: {}", responseBody);
            
            // 从响应中提取数据
            Map<String, Object> responseMap = objectMapper.readValue(responseBody, Map.class);
            Map<String, Object> hitsMap = (Map<String, Object>) responseMap.get("hits");
            Map<String, Object> totalMap = (Map<String, Object>) hitsMap.get("total");
            int total = ((Number) totalMap.get("value")).intValue();
            
            List<Map<String, Object>> hitsList = (List<Map<String, Object>>) hitsMap.get("hits");
            List<Content> contents = new ArrayList<>();
            
            log.info("ES搜索结果总数: {}, 当前页匹配数: {}", total, hitsList.size());
            
            for (Map<String, Object> hit : hitsList) {
                Map<String, Object> source = (Map<String, Object>) hit.get("_source");
                double score = ((Number) hit.get("_score")).doubleValue();
                Content content = objectMapper.convertValue(source, Content.class);
                log.debug("匹配内容: ID={}, 标题={}, 得分={}", content.getId(), content.getTitle(), score);
                contents.add(content);
            }
            
            // 构建分页结果
            PageResult<Content> pageResult = new PageResult<>(total, contents);
            
            // 缓存搜索结果
            cacheService.cacheSearchResult(cacheKey, pageResult, SEARCH_CACHE_EXPIRY);
            
            return Result.success(pageResult);
            
        } catch (IOException e) {
            log.error("搜索内容失败: {}", e.getMessage(), e);
            handleElasticsearchException("搜索内容失败", e);
            return Result.error("搜索失败：" + e.getMessage());
        }
    }
    
    @Override
    public Result<PageResult<Content>> semanticSearchContent(String query, int pageNum, int pageSize, double minScore) {
        if (!elasticsearchAvailable) {
            log.warn("Elasticsearch不可用，无法进行语义检索");
            return Result.error("Elasticsearch服务不可用，请使用普通搜索");
        }
        
        if (!chineseVectorService.isModelLoaded()) {
            log.warn("词向量模型未加载，无法进行语义检索，降级到普通搜索");
            return searchContent(query, pageNum, pageSize);
        }
        
        try {
            // 尝试从缓存中获取搜索结果
            String cacheKey = cacheService.generateSearchKey("semantic", query, pageNum, pageSize);
            PageResult<Content> cachedResult = cacheService.getCachedSearchResult(cacheKey);
            
            if (cachedResult != null) {
                log.info("使用缓存的语义搜索结果: {}", cacheKey);
                return Result.success(cachedResult);
            }
            
            log.info("缓存未命中，执行语义搜索: {}", cacheKey);
            
            // 计算起始位置
            int from = (pageNum - 1) * pageSize;
            
            // 为查询文本生成向量
            double[] queryVector = chineseVectorService.textToVector(query);
            
            // 构建向量搜索查询
            Map<String, Object> queryMap = new HashMap<>();
            queryMap.put("from", from);
            queryMap.put("size", pageSize);
            
            Map<String, Object> queryObj = new HashMap<>();
            Map<String, Object> knnObj = new HashMap<>();
            
            Map<String, Object> fieldQuery = new HashMap<>();
            fieldQuery.put("field", "content_vector");
            fieldQuery.put("query_vector", queryVector);
            fieldQuery.put("k", pageSize * 5); // 获取更多候选，以便过滤
            fieldQuery.put("num_candidates", pageSize * 10);
            
            knnObj.put("field", "content_vector");
            knnObj.put("query_vector", queryVector);
            knnObj.put("k", pageSize * 5);
            knnObj.put("num_candidates", pageSize * 10);
            
            Map<String, Object> filterObj = new HashMap<>();
            Map<String, Object> termObj = new HashMap<>();
            termObj.put("isDeleted", false);
            filterObj.put("term", termObj);
            
            knnObj.put("filter", filterObj);
            
            queryObj.put("knn", knnObj);
            queryMap.put("query", queryObj);
            
            // 执行搜索
            String queryJson = objectMapper.writeValueAsString(queryMap);
            Request request = new Request("POST", "/" + CONTENT_INDEX + "/_search");
            request.setEntity(new NStringEntity(queryJson, ContentType.APPLICATION_JSON));
            Response response = restClient.performRequest(request);
            
            // 解析结果
            String responseBody = EntityUtils.toString(response.getEntity());
            
            // 从响应中提取数据
            Map<String, Object> responseMap = objectMapper.readValue(responseBody, Map.class);
            Map<String, Object> hitsMap = (Map<String, Object>) responseMap.get("hits");
            List<Map<String, Object>> hitsList = (List<Map<String, Object>>) hitsMap.get("hits");
            
            List<Content> contents = new ArrayList<>();
            
            for (Map<String, Object> hit : hitsList) {
                // 获取得分
                double score = ((Number) hit.get("_score")).doubleValue();
                
                // 只保留得分高于阈值的结果
                if (score >= minScore) {
                    Map<String, Object> source = (Map<String, Object>) hit.get("_source");
                    Content content = objectMapper.convertValue(source, Content.class);
                    contents.add(content);
                }
            }
            
            // 构建分页结果
            PageResult<Content> pageResult = new PageResult<>(contents.size(), contents);
            
            // 缓存搜索结果
            cacheService.cacheSearchResult(cacheKey, pageResult, SEARCH_CACHE_EXPIRY);
            
            return Result.success(pageResult);
            
        } catch (IOException e) {
            handleElasticsearchException("语义搜索内容失败", e);
            return Result.error("语义搜索失败：" + e.getMessage());
        }
    }
    
    @Override
    public boolean updateContentVector(Content content) {
        if (!elasticsearchAvailable || !chineseVectorService.isModelLoaded()) {
            log.warn("Elasticsearch或词向量模型不可用，无法更新内容向量");
            return false;
        }
        
        try {
            // 生成内容向量
            String textForVector = content.getTitle() + " " + content.getDescription();
            double[] vector = chineseVectorService.textToVector(textForVector);
            
            // 构建更新请求
            Map<String, Object> updateMap = new HashMap<>();
            Map<String, Object> docMap = new HashMap<>();
            docMap.put("content_vector", vector);
            updateMap.put("doc", docMap);
            
            String updateJson = objectMapper.writeValueAsString(updateMap);
            Request request = new Request("POST", "/" + CONTENT_INDEX + "/_update/" + content.getId());
            request.setEntity(new NStringEntity(updateJson, ContentType.APPLICATION_JSON));
            
            Response response = restClient.performRequest(request);
            int statusCode = response.getStatusLine().getStatusCode();
            
            log.info("更新内容向量结果，ID: {}, 状态码: {}", content.getId(), statusCode);
            return statusCode == 200;
            
        } catch (IOException e) {
            handleElasticsearchException("更新内容向量失败", e);
            return false;
        }
    }
    
    @Override
    public int batchUpdateContentVectors(List<Content> contents) {
        if (!elasticsearchAvailable || !chineseVectorService.isModelLoaded()) {
            log.warn("Elasticsearch或词向量模型不可用，无法批量更新内容向量");
            return 0;
        }
        
        int successCount = 0;
        
        try {
            StringBuilder bulkRequestBody = new StringBuilder();
            
            for (Content content : contents) {
                // 生成内容向量
                String textForVector = content.getTitle() + " " + content.getDescription();
                double[] vector = chineseVectorService.textToVector(textForVector);
                
                // 构建更新请求
                Map<String, Object> updateMap = new HashMap<>();
                Map<String, Object> docMap = new HashMap<>();
                docMap.put("content_vector", vector);
                updateMap.put("doc", docMap);
                
                // 添加到批量请求
                String updateAction = "{\"update\":{\"_id\":\"" + content.getId() + "\"}}\n";
                String updateDoc = objectMapper.writeValueAsString(updateMap) + "\n";
                
                bulkRequestBody.append(updateAction);
                bulkRequestBody.append(updateDoc);
            }
            
            // 执行批量更新
            Request request = new Request("POST", "/" + CONTENT_INDEX + "/_bulk");
            request.setEntity(new NStringEntity(bulkRequestBody.toString(), ContentType.APPLICATION_JSON));
            
            Response response = restClient.performRequest(request);
            String responseBody = EntityUtils.toString(response.getEntity());
            
            // 解析批量更新结果
            Map<String, Object> responseMap = objectMapper.readValue(responseBody, Map.class);
            boolean hasErrors = (boolean) responseMap.get("errors");
            
            if (!hasErrors) {
                successCount = contents.size();
            } else {
                // 统计成功的数量
                List<Map<String, Object>> items = (List<Map<String, Object>>) responseMap.get("items");
                for (Map<String, Object> item : items) {
                    Map<String, Object> updateResult = (Map<String, Object>) item.get("update");
                    if ((int) updateResult.get("status") >= 200 && (int) updateResult.get("status") < 300) {
                        successCount++;
                    }
                }
            }
            
            log.info("批量更新内容向量完成，总数: {}, 成功数: {}", contents.size(), successCount);
            
        } catch (IOException e) {
            handleElasticsearchException("批量更新内容向量失败", e);
        }
        
        return successCount;
    }
    
    private void handleElasticsearchException(String message, Exception e) {
        log.error(message, e);
        if (e instanceof IOException) {
            if (e.getMessage().contains("Connection is closed") || 
                e.getMessage().contains("Connection refused") ||
                e.getMessage().contains("No route to host")) {
                log.error("Elasticsearch连接失败，标记为不可用");
                elasticsearchAvailable = false;
            }
        }
    }

    /**
     * 刷新索引，确保更改立即可见
     * @param operationType 操作类型（添加/更新/删除）
     * @param contentId 内容ID
     */
    private void refreshIndex(String operationType, Long contentId) {
        try {
            Request refreshRequest = new Request("POST", "/" + CONTENT_INDEX + "/_refresh");
            Response refreshResponse = restClient.performRequest(refreshRequest);
            int refreshStatusCode = refreshResponse.getStatusLine().getStatusCode();
            
            if (refreshStatusCode >= 200 && refreshStatusCode < 300) {
                log.info("索引刷新成功，{}的内容ID: {} 现在可以被正确搜索", operationType, contentId);
            } else {
                log.warn("索引刷新返回非成功状态码: {}, 操作类型: {}, 内容ID: {}", 
                        refreshStatusCode, operationType, contentId);
            }
        } catch (IOException e) {
            log.error("刷新索引失败，操作类型: {}, 内容ID: {}, 错误: {}", 
                    operationType, contentId, e.getMessage(), e);
            // 刷新失败不影响主流程
        }
    }

    @Override
    public boolean refreshContentIndex() {
        if (!elasticsearchAvailable) {
            log.warn("Elasticsearch不可用，无法刷新索引");
            return false;
        }

        try {
            Request refreshRequest = new Request("POST", "/" + CONTENT_INDEX + "/_refresh");
            Response refreshResponse = restClient.performRequest(refreshRequest);
            int refreshStatusCode = refreshResponse.getStatusLine().getStatusCode();
            
            if (refreshStatusCode >= 200 && refreshStatusCode < 300) {
                log.info("手动刷新索引成功，状态码: {}", refreshStatusCode);
                return true;
            } else {
                log.warn("手动刷新索引返回非成功状态码: {}", refreshStatusCode);
                return false;
            }
        } catch (IOException e) {
            log.error("手动刷新索引失败: {}", e.getMessage(), e);
            handleElasticsearchException("刷新索引失败", e);
            return false;
        }
    }

    @Override
    public boolean isContentIndexed(Long contentId) {
        if (!elasticsearchAvailable) {
            log.warn("Elasticsearch不可用，无法检查内容是否已索引");
            return false;
        }

        try {
            Request request = new Request("HEAD", "/" + CONTENT_INDEX + "/_doc/" + contentId);
            Response response = restClient.performRequest(request);
            int statusCode = response.getStatusLine().getStatusCode();
            
            boolean exists = statusCode == 200;
            log.info("检查内容ID: {} 是否已索引: {}", contentId, exists);
            return exists;
        } catch (ResponseException e) {
            if (e.getResponse().getStatusLine().getStatusCode() == 404) {
                log.info("内容ID: {} 未在索引中找到", contentId);
                return false;
            }
            log.error("检查内容是否已索引失败，ID: {}, 错误: {}", contentId, e.getMessage());
            return false;
        } catch (IOException e) {
            log.error("检查内容是否已索引失败，ID: {}, 错误: {}", contentId, e.getMessage());
            return false;
        }
    }
    
    @Override
    public int rebuildContentIndex() {
        if (!elasticsearchAvailable) {
            log.warn("Elasticsearch不可用，无法重建索引");
            return 0;
        }
        
        try {
            // 先删除索引
            try {
                Request deleteRequest = new Request("DELETE", "/" + CONTENT_INDEX);
                restClient.performRequest(deleteRequest);
                log.info("成功删除索引: {}", CONTENT_INDEX);
            } catch (ResponseException e) {
                if (e.getResponse().getStatusLine().getStatusCode() != 404) {
                    throw e;
                }
                log.info("索引不存在，无需删除: {}", CONTENT_INDEX);
            }
            
            // 创建新索引
            createContentIndex();
            
            // 获取所有未删除的内容
            // 这里假设有一个contentMapper可以获取所有内容
            // 注意：这里需要分批处理，避免一次加载过多数据
            log.info("开始重建内容索引");
            
            // 由于这里可能需要访问contentMapper，我们应该注入ContentMapper
            // 这里为简化起见，我们创建一个新的API端点来调用此方法，并在Controller中注入ContentMapper
            return 0;
        } catch (IOException e) {
            log.error("重建索引失败: {}", e.getMessage(), e);
            handleElasticsearchException("重建索引失败", e);
            return 0;
        }
    }

    @Override
    public org.elasticsearch.client.RestClient getRestClient() {
        return this.restClient;
    }
} 